﻿var triRunner = new Worker("js/TriRunner.js");
triRunner.addEventListener('message', function (e) {
	//console.log("from subthread", e);
	if (e.data.command == "note") {
		//console.log("resampled result", e);
		for (var i = 0; i < triBeeps.length; i++) {
			if (triBeeps[i].key == e.data.key
				 && triBeeps[i].pitch == e.data.pitch
				 && triBeeps[i].step == e.data.step) {
				var b = triBeeps[i];
				//console.log("resampled result", e, "for", b);
				var channelFloat32Array = b.buffer.getChannelData(0);
				for (i = 0; i < e.data.resultFloat32Array.length; i++) {
					channelFloat32Array[i] = e.data.resultFloat32Array[i];
				}
				b.ready = true;
				break;
			}
		}
	} else {
		console.log("unknown", e);
	}
}, false);
function Beep5() {
	var me = this;
	me.step = 0;
	me.ready = false;
	me.beep = function () {
		//
	};
	return me;
}
function Audio5() {
	var me = this;
	me.audioContext = null;
	me.audioBufferSourceNode = null;

	me.resample = function (sampleFloat32Array, resultFloat32Array //
	, correction, startVolume, tempo, length, startPitch, loopStart, loopEnd, slideToPitch) {
		//console.log("resample",sampleFloat32Array, correction, startVolume, tempo, length, startPitch, loopStart, loopEnd, slideToPitch);
		var len16 = 44100 * (60.0 / 4.0) / tempo;
		var sixteenth = len16 * length;
		var decayRatio = 0.999;
		var startFrequency = notesFrequencies[Math.floor(startPitch + 60 + correction / 100.0)];
		var endFrequency = notesFrequencies[Math.floor(slideToPitch + 60 + correction / 100.0)];
		var stepDelta = startFrequency / defaultSampleFrequency;
		var endDelta = endFrequency / defaultSampleFrequency;
		var stepShift = (endDelta - stepDelta) / sixteenth;
		//var resultFloat32Array = new Float32Array(sixteenth + len16 * 1);
		var volume = startVolume;
		if (loopStart > 8 //
			 && loopStart < resultFloat32Array.length
			 && loopEnd < sampleFloat32Array.length
			 && loopStart < loopEnd) {

			var index = 0;
			for (var i = 0; i < loopStart; i++) {
				if (i >= sampleFloat32Array.length) {
					break;
				} else {
					if (i > sixteenth) {
						volume = volume * decayRatio;
					}
					resultFloat32Array[i] = sampleFloat32Array[Math.floor(index)] * volume;
				}
				index = index + stepDelta;
				stepDelta = stepDelta + stepShift;
			}
			for (var i = loopStart; i < resultFloat32Array.length; i++) {
				if (i > sixteenth) {
					volume = volume * decayRatio;
				}
				resultFloat32Array[i] = sampleFloat32Array[Math.floor(index)] * volume;
				if (index >= loopEnd) {
					index = index - (loopEnd - loopStart);
				}
				index = index + stepDelta;
				stepDelta = stepDelta + stepShift;
			}
		} else {
			var index = 0;
			for (var i = 0; i < resultFloat32Array.length; i++) {
				if (i >= sampleFloat32Array.length) {
					break;
				} else {
					if (i > sixteenth) {
						volume = volume * decayRatio;
					}
					resultFloat32Array[i] = sampleFloat32Array[Math.floor(index)] * volume;
				}
				index = index + stepDelta;
				stepDelta = stepDelta + stepShift;
			}
		}
		//return resultFloat32Array;
	};
	me.playSample = function (sampleFloat32Array) {
		console.log("start Audio5.playSample");
		me.stop();
		me.initAudioContext();
		var audioBuffer = me.audioContext.createBuffer(1, sampleFloat32Array.length, 44100);
		var channelFloat32Array = audioBuffer.getChannelData(0);
		for (i = 0; i < sampleFloat32Array.length; i++) {
			channelFloat32Array[i] = sampleFloat32Array[i];
		}
		me.audioBufferSourceNode = me.audioContext.createBufferSource();
		me.audioBufferSourceNode.buffer = audioBuffer;
		me.audioBufferSourceNode.loop = false;
		me.audioBufferSourceNode.connect(me.audioContext.destination);
		me.audioBufferSourceNode.start(0);
		console.log("done Audio5.playSample");
	};
	me.renderKick = function (step, instrumentSample, tempo) {
		var len16 = 44100 * (60.0 / 4.0) / tempo;
		var sixteenth = len16 * 4;
		var audioBuffer = me.audioContext.createBuffer(1, sixteenth, 44100);
		var audioBufferSourceNode = me.audioContext.createBufferSource();
		audioBufferSourceNode.buffer = audioBuffer;
		audioBufferSourceNode.loop = false;
		audioBufferSourceNode.connect(me.audioContext.destination);
		//console.log(step);
		triRunner.postMessage({
			command : "note",
			step : step, //
			key : instrumentSample.key, //
			sampleFloat32Array : instrumentSample.float32Array, //
			resultFloat32Array : audioBuffer.getChannelData(0), //
			correction : instrumentSample.correction, //
			startVolume : instrumentSample.volume, //
			tempo : tempo, //
			length : 4, //
			startPitch : 60, //
			loopStart : 0, //
			loopEnd : 0, //
			slideToPitch : 60
		});
		var beep = new Beep5();
		beep.beep = function () {
			if (beep.ready) {
				audioBufferSourceNode.start(0);
			} else {
				console.log("skip");
			}
		};
		beep.buffer = audioBuffer;
		beep.step = step;
		beep.key = instrumentSample.key;
		beep.pitch = 60;
		triBeeps.push(beep);
	}
	me.renderNote = function (step, instrumentSample, tempo, length, pitchStart, pitchEnd) {
		var len16 = 44100 * (60.0 / 4.0) / tempo;
		var sixteenth = len16 * length;
		var audioBuffer = me.audioContext.createBuffer(1, sixteenth, 44100);
		var audioBufferSourceNode = me.audioContext.createBufferSource();
		audioBufferSourceNode.buffer = audioBuffer;
		audioBufferSourceNode.loop = false;
		audioBufferSourceNode.connect(me.audioContext.destination);
		/*
		me.resample(instrumentSample.float32Array, audioBuffer.getChannelData(0) //, instrumentSample.correction, instrumentSample.volume, tempo, length //, pitchStart, instrumentSample.startLoop, instrumentSample.endLoop, pitchEnd);
		 */
		triRunner.postMessage({
			command : "note",
			step : step, //
			key : instrumentSample.key, //
			sampleFloat32Array : instrumentSample.float32Array, //
			resultFloat32Array : audioBuffer.getChannelData(0), //
			correction : instrumentSample.correction, //
			startVolume : instrumentSample.volume, //
			tempo : tempo, //
			length : length, //
			startPitch : pitchStart, //
			loopStart : instrumentSample.startLoop, //
			loopEnd : instrumentSample.endLoop, //
			slideToPitch : pitchEnd

		});

		var beep = new Beep5();
		beep.beep = function () {
			if (beep.ready) {
				//console.log("play");
				audioBufferSourceNode.start(0);
				//beep.resampled.start(0);
			} else {
				console.log("skip");
			}
		};
		beep.buffer = audioBuffer;
		beep.step = step;
		beep.key = instrumentSample.key;
		beep.pitch = pitchStart;
		triBeeps.push(beep);
		return beep;
	};
	me.stop = function () {
		console.log("Audio5.stop");
		if (me.audioBufferSourceNode != null) {
			try {
				me.audioBufferSourceNode.stop(0);
				me.audioBufferSourceNode.disconnect(0);
				me.audioBufferSourceNode = null;
			} catch (ops) {
				console.log(ops);
			}
		}
	};
	me.initAudioContext = function () {
		if (me.audioContext == null) {
			try {
				console.log("Audio5.initAudioContext");
				window.AudioContext = window.AudioContext || window.webkitAudioContext;
				me.audioContext = new AudioContext();
			} catch (e) {
				console.log(e);
			}
		}
	};
	me.cleanUp = function () {};
	return me;
}
